package Datenbank;

import java.rmi.RemoteException;
import java.sql.*;
import java.util.*;
import Applikationslogik.*;

/**
 * Bildet Objekte des Typs Wiederholung auf der relationalen Datenbank ab.
 * Die Klasse beinhaltet Methoden und Objekte zum Anlegen, Ändern, Löschen und Suchen.
 *
 * @author Daniel Mossiossian & René van Straaten
 */
public class WiederholungMapper {
        private static WiederholungMapper wiederholungMapper = null;

    /**
     * Stellt sicher, dass nur eine Istanz von WiederholungMapper erzeugt wird.
     *
     * @return wiederholungMapper das wiederholungMapper- Objekt
     */
    public static WiederholungMapper WiederholungMapper() {
        if (wiederholungMapper == null) {
            wiederholungMapper = new WiederholungMapper();
        }

        return wiederholungMapper;
    }

    /**
    * Fügt ein neues Wiederholung- Objekt in die Datenbank ein.
    *
    * @param wh das das zu speichernde Wiederholung- Objekt
    * @return wh das bereits übergebene Objekt vom Typ Wiederholung
    */
    public Wiederholung insert(Wiederholung wh) {
        Connection con = DBConnection.connection();

        try {
            Statement stmt = con.createStatement();

            
             //Hier wird überprüft welche eintrag_id bisher die höhste ist.
            
            ResultSet rs = stmt.executeQuery(
                    "SELECT MAX(eintrag_id) AS maxid " +
                    "FROM Kalendereintrag");


            if (rs.next()) {
                try {
                    // Hier wird die bisher höhste vorhandene eintrag_id um 1 erhöht.
                     
                    wh.set_eintrag_id(rs.getInt("maxid") + 1);

                    stmt = con.createStatement();

                    // Die tatsächliche Einfügeoperation mit den übergebenden Attributen.
                     

                    stmt.executeUpdate("INSERT INTO Kalendereintrag (eintrag_id, typ, erinnerung, ort, start, ende, beschreibung, wiederholung, kategorie_id, person_id, serienmuster, anzahl) VALUES (" +
                            wh.get_eintrag_id() + ",'" +
                            "w" + "'," +
                            wh.get_erinnerung() + ",'" +
                            wh.get_ort() + "','" +
                            wh.get_start() + "','" +
                            wh.get_ende() + "','" +
                            wh.get_beschreibung() + "'," +
                            wh.get_wiederholung_id() + "," +
                            wh.get_kategorie() + "," +
                            wh.get_erstelltvon() + ",'" +
                            wh.get_serienmuster() + "'," +
                            wh.get_anzahl() + ")");

                    stmt.executeUpdate("INSERT INTO Teilnahme (kalender_id, eintrag_id, teilnahme) VALUES (" +
                            wh.get_kalender_id() + "," +
                            wh.get_eintrag_id() + "," +
                            "1" + ")");


                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (SQLException e2) {
            e2.printStackTrace();
        }


        // Rückgabe des angelegten Objekts wh von Typ Wiederholung
         
        return wh;
    }

    /**
     * Aktualisiert das übergebene Wiederholung- Objekt in der Datenbank.
     *
     * @param wh das zu aktualisierende Wiederholung- Objekt
     * @return wh das als Parameter übergebene Objekt des Typs Wiederholung
     */
    public Wiederholung update(Wiederholung wh) {
        /* Stellt durch Aufruf der connection() Methode der DBConnection-Klasse, die Verbindung zur Datenbank her. */
        Connection con = DBConnection.connection();

        try {
            // Leeres SQL-Statement stmt wird angelegt.
            Statement stmt = con.createStatement();

                   stmt.executeUpdate("UPDATE Kalendereintrag " +
                    "SET eintrag_id=" + wh.get_eintrag_id() + ", " +
                    "typ='w', " +
                    "erinnerung=" + wh.get_erinnerung() + ", " +
                    "ort='" + wh.get_ort() + "', " +
                    "start='" + wh.get_start() + "', " +
                    "ende='" + wh.get_ende() + "', " +
                    "beschreibung='" + wh.get_beschreibung() + "', " +
                    "wiederholung=" + wh.get_wiederholung_id() + ", " +
                    // "enddatum='null', " +
                    "kategorie_id=" + wh.get_kategorie() + ", " +
                    "person_id=" + wh.get_erstelltvon() + ", " +
                    "anzahl=" + wh.get_anzahl() + ", " +
                    "serienmuster='" + wh.get_serienmuster() + "' " +
                    "WHERE eintrag_id=" + wh.get_eintrag_id());


        } catch (SQLException e2) {
            e2.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // das als Parameter übergebende Objekt des Typs Wiederholung wird zurückgegeben
        return wh;
    }


    /**
     * Holt die kleinste eintrag_id vom Typ Wiederholung aus der Datenbank.
     *
     * @param wiederholung Wiederholung vom Typ int
     * @return result
     */
    public int get_lowest_eintragid_by_wh(int wiederholung) {
        Connection con = DBConnection.connection();
        int result = 0;
        try {
            Statement stmt = con.createStatement();

           
            ResultSet rs = stmt.executeQuery(
                    "SELECT MIN(eintrag_id) AS minid " +
                    "FROM Kalendereintrag WHERE wiederholung=" + wiederholung);


            if (rs.next()) {
                try {
                    
                    result = (rs.getInt("minid"));


                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (SQLException e2) {
            e2.printStackTrace();
        }

        return result;
    }

    /**
     * Holt die größte eintrag_id vom Typ Wiederholung aus der Datenbank.
     *
     * @return highest_id die Wiederholung mit der größten ID
     */
    public int get_highest_wh_id() {
        Connection con = DBConnection.connection();
        int highest_id = 0;
        try {
            Statement stmt = con.createStatement();

            
            ResultSet rs = stmt.executeQuery(
                    "SELECT MAX(wiederholung) AS maxid " +
                    "FROM Kalendereintrag");


            if (rs.next()) {
                try {
                    
                    highest_id = (rs.getInt("maxid"));


                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (SQLException e2) {
            e2.printStackTrace();
        }
        return highest_id;
    }

    /**
     * Löscht alle Einträge, die die übergebene Wiederholungs ID besitzen
     *
     * @param wiederholung
     */
    public void delete_by_wiederholung(int wiederholung) {
        Connection con = DBConnection.connection();

        try {
            // Leeres SQL-Statement stmt wird angelegt.
            Statement stmt = con.createStatement();

            // Löschen in der Tabelle Teilnahme verknüpft mit INNERJOIN auf Kalendereintrag Tabelle
            stmt.executeUpdate("DELETE Teilnahme.* FROM Teilnahme " +
                    "INNER JOIN Kalendereintrag ON Teilnahme.eintrag_id = Kalendereintrag.eintrag_id " +
                    "WHERE wiederholung=" + wiederholung);

            // Löschen in der Tabelle Kalendereintrag alle Einträge die die übergebene Wiederholungs ID besitzen
            stmt.executeUpdate("DELETE FROM Kalendereintrag " +
                    "WHERE wiederholung=" + wiederholung);



        } catch (SQLException e2) {
            e2.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Findet alle Wiederholungen anhand der ID.
     *
     * @param id die ID der Wiederholung
     */
    public Wiederholung findbyid(int id) {
        Connection con = DBConnection.connection();

        try {
            Statement stmt = con.createStatement();

            ResultSet rs = stmt.executeQuery(
                    "SELECT * FROM Kalendereintrag " +
                    "WHERE eintrag_id =" + id);

           
            if (rs.next()) {
                try {
                    System.out.println(id);
                    WiederholungImpl wh = new WiederholungImpl();
                    wh.set_eintrag_id(rs.getInt("eintrag_id"));
                    wh.set_erinnerung(rs.getInt("erinnerung"));
                    wh.set_ort(rs.getString("ort"));
                    wh.set_start(rs.getTimestamp("start"));
                    wh.set_ende(rs.getTimestamp("ende"));
                    wh.set_beschreibung(rs.getString("beschreibung"));
                    wh.set_wiederholung_id(rs.getInt("wiederholung"));
                    wh.set_kategorie(rs.getInt("kategorie_id"));
                    wh.set_erstelltvon(rs.getInt("person_id"));
                    wh.set_serienmuster(rs.getString("serienmuster").charAt(0));
                    wh.set_anzahl(rs.getInt("anzahl"));


                    try {
                        Statement stmt2 = con.createStatement();

                        ResultSet rs2 = stmt2.executeQuery(
                                "SELECT kalender_id FROM Teilnahme " +
                                "WHERE eintrag_id =" + wh.get_eintrag_id());

                       

                        while (rs2.next()) {
                            try {
                                wh.set_kalender_id(rs2.getInt("kalender_id"));
                                return wh;
                            } catch (Exception e) {
                                e.printStackTrace();
                                return null;
                            }
                        }

                    } catch (SQLException e2) {
                        e2.printStackTrace();
                        return null;
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }

        } catch (SQLException e2) {
            e2.printStackTrace();
            return null;
        }

        return null;
    }

    /**
     * Findet alle Wiederholungen für eine Person anhand der ID.
     *
     * @param person_id die ID der Person
     * @return Vektor mit allen Wiederholungen
     * @throws RemoteException
     */
    public Vector <Wiederholung> findall_wiederholungen_person(int person_id) throws RemoteException {
        Connection con = DBConnection.connection();
        Vector <Wiederholung> result = new Vector();
        Vector <Wiederholung> result_wiederholung = new Vector();

        try {
            Statement stmt = con.createStatement();


            ResultSet rs = stmt.executeQuery(

                    "SELECT * " +
                    "FROM Kalendereintrag " +
                    "WHERE typ='w' AND person_id=" + person_id + " ORDER BY wiederholung ASC" +
                    "");

            while (rs.next()) {
                try {
                    Wiederholung wh = new WiederholungImpl();
                    wh.set_beschreibung(rs.getString("beschreibung"));
                    wh.set_eintrag_id(rs.getInt("eintrag_id"));
                    wh.set_ende(rs.getTimestamp("ende"));
                    wh.set_erinnerung(rs.getInt("erinnerung"));
                    wh.set_erstelltvon(rs.getInt("person_id"));
                    wh.set_kalender_id(0); //Setzen wir hier in dem Fall nicht, da dieser keine Rolle spielt
                    wh.set_kategorie(rs.getInt("kategorie_id"));
                    wh.set_ort(rs.getString("ort"));
                    wh.set_start(rs.getTimestamp("start"));
                    wh.set_serienmuster(rs.getString("serienmuster").charAt(0));
                    wh.set_anzahl(rs.getInt("anzahl"));
                    wh.set_wiederholung_id(rs.getInt("wiederholung"));

                   // Wir fügen pro Wiederholung nur EINEN Eintrag dem Vector hinzu
                    if(result.size() > 0)
                        {
                        if(rs.getInt("wiederholung") == result.lastElement().get_wiederholung_id())
                        System.out.println("Kalendereintrag mit der WiederholungsID: " + rs.getInt("wiederholung") + " ist bereits im Vektor und wird nicht hinzugefügt" );
                        else
                        result.addElement(wh);
                        }
                    else
                    {
                        result.addElement(wh);
                    }


                  
                } catch (Exception e) {
                    e.printStackTrace();
                    //Bei einer evtl. Exception wird die while-Schleife abgebrochen.
                    break;
                }

            }
        } catch (SQLException e2) {
            e2.printStackTrace();
        }
        // Ergebnisvektor vom Typ Wiederholung wird zurückgeben.
        return result;

    }

    /**
     * Checkt, ob das neugesetzte Start- und Enddatum nicht bereits vergeben sind.
     *
     * @param start Startzeit vom Typ Timestamp
     * @param ende Endzeit vom Typ Timestamp
     * @param kalender_id ID des Kalenders vom Typ int
     * @param eintrag_id ID des Eintrags vom Typ int
     * @param wiederholung Wiederholugn vom Typ int
     * @return true, falls nicht vergeben ist, sonst false
     */
    public boolean check_datum_available_at_update_wh(Timestamp start, Timestamp ende, int kalender_id, int eintrag_id, int wiederholung) {
        Connection con = DBConnection.connection();
        boolean result = false;

        try {
            Statement stmt = con.createStatement();

            System.out.println("Übergebene Eintrag_ID: " + eintrag_id);

            ResultSet rs = stmt.executeQuery(

            "SELECT COUNT(*) AS count FROM Kalendereintrag INNER JOIN Teilnahme ON Kalendereintrag.eintrag_id = Teilnahme.eintrag_id " +
                    "WHERE kalender_id=" + kalender_id + " AND wiederholung!=" + wiederholung + " AND ( ('" +
                    start + "' BETWEEN Kalendereintrag.start AND Kalendereintrag.ende ) OR ('" +
                    ende + "' BETWEEN Kalendereintrag.start AND Kalendereintrag.ende) OR ('" +
                    start + "' < Kalendereintrag.start AND '" + ende + "' > Kalendereintrag.ende))");

             while (rs.next()) {
            int ueberschneidungen = rs.getInt("count");
            System.out.println("Errechnete Überschneidungen: " + ueberschneidungen);
            System.out.println("Übergebene Kalender_ID: " + kalender_id);

            if(ueberschneidungen > 0)
            result = true;
        }
        } catch (SQLException e2) {
            e2.printStackTrace();
        }
        return result;
    }
}
